<?

/**
 *  This collection of functions (libary) is licensed under GPL2.
 *  See LICENSE or www.gnu.org for more details.
 *
 *  @author Jyry Kuukkanen
 *  $Id: dzitu.php 595 2006-04-03 16:00:47Z jyry $
 */


include_once("soset.php");
include_once("soarrayset.php");
include_once("sostring.php");
include_once("sogeneric.php");


/* Blocks */
define(DZI_BLOCK_IDS, "control data data"); /** block ids */
define(DZI_CONTROL, "control");        /** only to make code more readable */
define(DZI_DATA, "data");              /** only to make code more readable */
define(DZI_PREFICIES, "DZC DZD DZB");  /** C for control block and D and B for
                                        * data -- the count must match with
                                        * DZI_BLOCK_IDS */


/** Class to transport data between Kone and other parts.
 *  Class includes two basic datastructures the other is for control data
 *  the other contains the data to send.
 *
 *  Class contains functionality to encode and decode the data it contains.
 *  @var array $__Blocks An array of soSet objects, Control and data blocks
 *  @var array $__BLOCK_IDS BlockID defines, php does not support array defines
 *  @var array $__BLOCK_IDS Preficies defines, php does not support array
 *      defines
 *  @var string Column delimiter string when en/decoding
 */
class dzItu {
    var $__Blocks;
    var $__BLOCK_IDS;
    var $__PREFICIES;
    var $ColDelim = "&";


    /** Constructor
     *  @param string $UrlString Url encoded string of fields
     */
    function dzItu($UrlString = "") {
        $this->__BLOCK_IDS = explode(" ", DZI_BLOCK_IDS);
        $this->__PREFICIES = explode(" ", DZI_PREFICIES);
        $this->emptyItu();
        if ($UrlString != "") $this->decode($UrlString);
    } // dzItu


    /** Empties all blocks in dzItu.
     */
    function emptyItu() {
        foreach ($this->__BLOCK_IDS as $block_id) {
            $this->__Blocks[$block_id] = new soArraySet();
        }; // foreach
    } // emptyItu


    /** discards the payload Itu contains. Leaves control data untouched.
     */
    function discardPayload() {
        $this->__Blocks[DZI_DATA] = new soArraySet();
    } // discardPayload


    /** Get a block (control/data).
     *  @param DZI_* $BlockID BlockID: DZI_CONTROL or DZI_DATA
     *  @return any soArraySet Returns the block as a soSet object or NULL
     *      when BlockID is unknown.
     */
    function getBlock($BlockID) {
        if (!$this->isBlock($BlockID)) return NULL;
        return $this->__Blocks[$BlockID];
    } // getBlock


    /** Stores a block (control/data).
     *  >$BlockID:DZI_* BlockID: DZI_CONTROL or DZI_DATA
     *  >$Value:soArraySet/any A value (a set) to store.
     *  <:bool Returns true(1) on success or false(0) when BlockID in unknown
     */
    function setBlock($BlockID, $Value) {
        if (!$this->isBlock($BlockID)) return 0; // <-- EXIT
        if (!in_array(soGetClass($Value),
            array('soarrayset', 'soset'))) {
            $Value = new soArraySet();
        };
        $this->__Blocks[$BlockID] = $Value;
        return 1;
    } // setBlock


    /** Get a block (control/data) column).
     *  @param DZI_* $BlockID BlockID: DZI_CONTROL or DZI_DATA
     *  @param string $ColID Column ID in the block.
     *  @return array/any Returns the block column as an array, or NULL on
     *      error (due to bad block or col ID)
     */
    function getBlockItem($BlockID, $ColID) {
        if (!$this->isBlock($BlockID)) return 0;
        $result = $this->__Blocks[$BlockID]->getItem($ColID);
        if ($this->__Blocks[$BlockID]->Error) return NULL; // <-- EXIT
        return $result;
    } // getBlockItem


    /** Checks whether a block item key has a value set.
     *  @param DZI_* $BlockID BlockID: DZI_CONTROL or DZI_DATA
     *  @param string $ColID Column ID in the block.
     *  @return bool True if item exists, otherwise false.
     */
    function isBlockItem($BlockID, $ColID) {
        if (($this->isBlock($BlockID)) &&
            ($this->__Blocks[$BlockID]->itemExists($ColID))) {
            $result = 1;
        } else {
            $result = 0;
        };

        return $result;
    } // isBlockItem


    /** Gets an item from block at certain position.
     *  This extends getBlockItem as ResultPos specifies which array element
     *      to return.
     *  @param DZI_* $BlockID BlockID: DZI_CONTROL or DZI_DATA
     *  @param string $ColID Column ID in the block.
     *  @param int $Rowno Row no. to return value from.
     *  @return mixed Returns an array element of the block item (an array) or
     *      NULL if ResultPos is out of range.
     */
    function getBlockItemAt($BlockID, $ColID, $RowNo = 0) {
        if ((!$this->isBlock($BlockID)) ||
            ($ResultPos < 0)) return NULL; // <-- EXIT

        return $this->__Blocks[$BlockID]->getArrayItem($ColID, $RowNo);
    } // getBlockItemAt


    /** Stores a block (control/data) column.
     *  The value to store can be either array or not. If it is not
     *  the value is set the only element in an array and stored.
     *  This is to make method call shorter in case that only one single
     *  control data is stored.
     *  @param DZI_* $BlockID BlockID: DZI_CONTROL or DZI_DATA
     *  @param string $ColID Column ID in the block.
     *  @param array||any $Value Value (a set) to store.
     *  @param bool $Replace When set, replaces an existing value in the block,
     *      otherwise skips the assignment.
     *  @return bool Returns true(1) on success or false(0) when BlockID in
     *      unknown or when Replace == 0 and an column already has a value.
     */
    function setBlockItem($BlockID, $ColID, $Value, $Replace = 1) {
        if (!$this->isBlock($BlockID)) return 0;
        if (!is_array($Value))
            $Value = array($Value);
        return $this->__Blocks[$BlockID]->setItem($ColID, $Value, $Replace);
    } // setBlockItem


    /** Clears a block.
     *  @param DZI_* $BlockID BlockID: DZI_CONTROL or DZI_DATA
     *  @return bool Returns false when BlockID is unknown, otherwise true.
     */
    function clearBlock($BlockID) {
        if (!$this->isBlock($BlockID)) return 0;
        $this->__Blocks[$BlockID]->clear();
        return 1;
    } // clearBlock


    /** Checks for BlockID
     *  @param DZI_* $BlockID DZI_DATA or DZI_CONTROL
     *  @return bool Returns true(1) if BlockID is valid, otherwise false(0).
     */
    function isBlock($BlockID) {
        $pos = soArrayFind($this->__BLOCK_IDS, $BlockID);
        return ($pos != -1);
    } // isBlock


    /** Encodes the class as an url encoded string.
     *  @return string Returns the essestials of the class as a URL encoded
     *  string.
     */
    function encode() {
        $result = "";
        $icount = count($this->__Blocks);

        for ($i = 0; $i < $icount; $i++) {
            $block = &$this->__Blocks[$this->__BLOCK_IDS[$i]];
            $keys = $block->getKeys();
            foreach ($keys as $key) {
                $values = implode(SO_URL_ARRAY_DELIM, $block->getItem($key));
                $values = urlencode($values);
                $key = urlencode(str_replace(".", "/", $key));
                $result = soJoinStr($result, $this->ColDelim,
                                    $this->__PREFICIES[$i].
                                    "_$key=$values", 1);
            }; // foreach key
        }; // foreach block

        return $result;
    } // encode



    /** Decodes an url encoded string into the blocks.
     *  @return string $UrlString URL encoded string to decode.
     */
    function decode($UrlString) {
        $cols = soExplode($UrlString, $this->ColDelim);
        foreach ($cols as $col) {
            /* split key and value DZx_key=value*/
            $item = soSplitStr($col, "=", 1, 0);
            if (count($item)) {
                /* Split data/control col's prefix and name (DZx_name) */
                $key = soSplitStr($item[0], "_", 1, 0);

                /* sort out block: control/data - unknown == data */
                $pos = soArrayFind($this->__PREFICIES, $key[0]);
                if ($pos == -1) $pos = 1;
                $block = &$this->__Blocks[$this->__BLOCK_IDS[$pos]];

                /* bindata is decoded differently */
                if ($pos == 2) {
                    $values = soUrlDecodeArray($item[1]);
                } else {
                    $values = soExplode(urldecode($item[1]),
                                                  SO_URL_ARRAY_DELIM);
                }; // if bindata/other

                /* "table.column" does not survive php's GET_HTTP_VARS
                 *  or POST_HTTPD_VARS and thus "." in such a table.col
                 *  notation must be replaced by "/". The following line
                 *  restores the dots back in. */
                $key[1] = str_replace("/", ".", urldecode($key[1]));

                $block->setItem($key[1], $values);
            }; // if count
        }; // foreach
    } // decode


    /** Dumps the object as a string.
     *  @param string ColDelim String to delimit one col from another.
     *  @param string RowDelim String to delimit one row from another inside a
     *  column.
     *  @return string Returns the whole object as a string
     */
    function dump($RowDelim = " | ", $ColDelim = " <-/\n") {

        $result = "";
        $icount = count($this->__Blocks);
        for ($i = 0; $i < $icount; $i++) {
            $result .= $this->__BLOCK_IDS[$i]."\n";
            $block = &$this->__Blocks[$this->__BLOCK_IDS[$i]];
            $keys = $block->getKeys();
            foreach ($keys as $key) {
                $col = $block->getItem($key);
                if (count($col)) $result .= $key." = ".
                                 implode($RowDelim, $col);
                $result .= $ColDelim;
                }; // foreach key
        }; // foreach block

        return $result;
    } // dump


    /** Gets the whole object as string.
     *  This is used for outputting the object.
     *  @param string ColDelim String to delimit one column from another.
     *  @return string Returns the whole object as a string
     */
    function toString($ColDelim = "\n", $ValDelim = ":") {
        $result = "";

        $icount = count($this->__Blocks);
        for ($i = 0; $i < $icount; $i++) {
            $block = &$this->__Blocks[$i];

            $keys = $block->getKeys();
            foreach ($keys as $key) {
                $col = $block->getItem($key);
                if (count($col)) {
                    $result .= $this->__PREFICIES[$i]."_$key=".
                               implode($ValDelim, $col).$ColDelim;
                };
            }; // foreach

        }; // for $i

        return $result;
    } // toString

} // class dzItu

?>
